#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

using Weazel.Math;

namespace Weazel.Gezel.Model
{
    /// <summary>
    /// Enumerates the set of possible types of expressions.
    /// </summary>
    public enum ExpressionType
    {
        Generic,
        Assignment,
        Constant,
        Cast,
        Str,
        Ternary,
        List,
        Index,
        Range,
        DisplayDirective,
        DatapathDirective,
        FinishDirective,
        CycleDirective,
        ToggleDirective,
        SfgDirective,
        HexDirective,
        BinDirective,
        DecDirective,
        Identifier,
        Add,
        Sub,
        UnarySub,
        Mul,
        Div,
        Mod,
        And,
        Not,
        Ior,
        Xor,
        Lookup,
        ShiftRight,
        ShiftLeft,
        Concatenation,

        // comparisons
        Eq,
        Neq,
        Lt,
        Gt,
        Lte,
        Gte,

        Unknown
    }

    /// <summary>
    /// This delegate can used by code to recursivily walk through an expression tree.
    /// </summary>
    /// <param name="expression">The current expression</param>
    /// <param name="parent">Parent of the current expression (may be null)</param>
    /// <param name="parameter">User paramter</param>
    public delegate void ExpressionDelegate(Expression expression, Expression parent, object parameter);

    /// <summary>
    /// The Expression class is the base for all the types of
    /// expressions which are found in signalflowgraphs and finite-
    /// state machine conditional expressions.
    /// </summary>
    public abstract partial class Expression : AbstractEntity<CommonEntity>
    {
        /// <summary>
        /// The type of expression, no need to encapsulate as
        /// propery since it's immutable.
        /// </summary>
        private ExpressionType expressionType;
        public ExpressionType ExpressionType
        {
            get { return expressionType; }
            protected set { expressionType = value; }
        }

        /// <summary>
        /// Initializes the expression with the specified type and
        /// no parent.
        /// </summary>
        /// <param name="exprType"></param>
        protected Expression(ExpressionType exprType)
            : base(null)
        {
            this.expressionType = exprType;
            this.startPosition = null;
            this.endPosition = null;
        }

        protected Expression(
            ExpressionType exprType,
            Position startPosition,
            Position endPosition
        )
            : base(null)
        {
            this.expressionType = exprType;
            this.startPosition = startPosition;
            this.endPosition = endPosition;
        }

        public abstract int Width
        {
            get;
        }

        public abstract bool Signed
        {
            get;
        }

        public abstract void RecursivilyInvokeDelegate(
            ExpressionDelegate expressionDelegate,
            Expression parent,
            object parameter
        );

        public abstract Expression Clone();

        public abstract void GetDependentLeafExpressions(ref List<LeafExpression> leafExpressions);
    }

    /// <summary>
    /// The LeafExpression is an expression which
    /// has no operands but provides a constant type 
    /// or references some kind of a signal.
    /// </summary>
    public partial class LeafExpression : Expression, ITypedEntity
    {
        /// <summary>
        /// The identifier, integer litteral or 
        /// litteral string
        /// </summary>
        public string value;
        public string Value
        {
            get { return value; }
            protected set { this.value = value; }
        }

        /// <summary>
        /// true iff the sign and width of this expression
        /// should be calculated based on the content of 'value' 
        /// in the verification step. Otherwise the user must supply
        /// both the desired width and sign.
        /// </summary>
        private bool userSetWidthAndSign = false;

        private bool signed;
        private int width;

        /// <summary>
        /// The referenced entity if LeafExpression is
        /// of type IdentifierExpression
        /// </summary>
        private ITypedEntity referencedEntity;
        public ITypedEntity ReferencedEntity
        {
            get
            {
                return referencedEntity;
            }
        }

        private Integer integerValue;
        public Integer IntegerValue
        {
            get
            {
                return integerValue;
            }
        }

        public override int Width
        {
            get
            {
                switch (ExpressionType)
                {
                    case ExpressionType.Constant:
                        {
                            System.Diagnostics.Debug.Assert(integerValue != null);
                            return userSetWidthAndSign ? width : integerValue.Width;
                        }
                    case ExpressionType.Identifier:
                        return referencedEntity.Width;
                    case ExpressionType.Str:
                        throw new NotSupportedException();
                    default:
                        throw new ApplicationException("internal error");
                }
            }
        }

        public override bool Signed
        {
            get
            {
                switch (ExpressionType)
                {
                    case ExpressionType.Constant:
                        {
                            System.Diagnostics.Debug.Assert(integerValue != null);

                            if (userSetWidthAndSign)
                                return signed;
                            else
                                return integerValue.Signed;
                        }
                    case ExpressionType.Identifier:
                        return referencedEntity.Signed;
                    case ExpressionType.Str:
                        throw new NotSupportedException();
                    default:
                        throw new ApplicationException("internal error");
                }
            }
        }

        public LeafExpression(ExpressionType exprType, string value)
            : base(exprType)
        {
            this.Value = value;
            this.userSetWidthAndSign = false;
        }

        public LeafExpression(
            ExpressionType exprType,
            string value,
            Position startPosition,
            Position endPosition
        )
            : base(exprType, startPosition, endPosition)
        {
            this.Value = value;
            this.userSetWidthAndSign = false;
        }

        public LeafExpression(
            ExpressionType exprType,
            string value,
            int width,
            bool signed,
            Position startPosition,
            Position endPosition
        )
            : this(exprType, value, startPosition, endPosition)
        {
            this.width = width;
            this.signed = signed;
            this.userSetWidthAndSign = true;
        }

        public LeafExpression(ExpressionType exprType)
            : base(exprType)
        {
            this.Value = null;
            this.userSetWidthAndSign = false;
        }

        public LeafExpression(
            ExpressionType exprType,
            Position startPosition,
            Position endPosition
        )
            : base(exprType, startPosition, endPosition)
        {
            this.Value = null;
            this.userSetWidthAndSign = false;
        }

        public override Expression Clone()
        {
            return new LeafExpression(ExpressionType, Value, startPosition, endPosition);
        }


        public override void GetDependentLeafExpressions(ref List<LeafExpression> leafExpressions)
        {
            leafExpressions.Add(this);
        }

        public override void RecursivilyInvokeDelegate(
            ExpressionDelegate expressionDelegate,
            Expression parent,
            object parameter
        )
        {
            expressionDelegate(this, parent, parameter);
        }

        public override string ToString()
        {
            if (ExpressionType == ExpressionType.Str)
                return string.Format("\"{0}\"", Value);
            else
                return Value;
        }
    }

    /// <summary>
    /// The cast expression changes the type of
    /// the expression which the cast operates on.
    /// </summary>
    public partial class CastExpression : Expression
    {
        public readonly Expression Child;
        private readonly bool signed;
        public override bool Signed
        {
            get
            {
                return signed;
            }
        }
        private readonly int width;
        public override int Width
        {
            get
            {
                return width;
            }
        }

        public CastExpression(int width, bool signed, Expression child)
            : base(ExpressionType.Cast)
        {
            this.Child = child;
            this.signed = signed;
            this.width = width;
        }

        public CastExpression(
            int width,
            bool signed,
            Expression child,
            Position startPosition,
            Position endPosition
        )
            : base(ExpressionType.Cast, startPosition, endPosition)
        {
            this.Child = child;
            this.signed = signed;
            this.width = width;
        }

        public override Expression Clone()
        {
            return new CastExpression(width, signed, Child.Clone());
        }

        public override void GetDependentLeafExpressions(ref List<LeafExpression> leafExpressions)
        {
            this.Child.GetDependentLeafExpressions(ref leafExpressions);
        }

        public override void RecursivilyInvokeDelegate(
            ExpressionDelegate expressionDelegate,
            Expression parent,
            object parameter
        )
        {
            expressionDelegate(this, parent, parameter);
            Child.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
        }

        public override string ToString()
        {
            return string.Format("({0}({1})){2}",
              signed ? "tc" : "ns",
              width,
              Child.ToString());
        }
    }

    public partial class RangeExpression : Expression
    {
        public readonly Expression Child;
        public readonly uint From;
        public readonly uint To;

        public override int Width
        {
            get
            {
                return (int)(To - From + 1);
            }
        }

        public override bool Signed
        {
            get
            {
                return Child.Signed;
            }
        }

        public RangeExpression(uint from, uint to, Expression child)
            : base(ExpressionType.Range)
        {
            this.Child = child;

            this.From = System.Math.Min(from, to);
            this.To = System.Math.Max(to, from);
        }

        public RangeExpression(
            uint from,
            uint to,
            Expression child,
            Position startPosition,
            Position endPosition
        )
            : base(ExpressionType.Range, startPosition, endPosition)
        {
            this.Child = child;
            this.From = System.Math.Min(from, to);
            this.To = System.Math.Max(to, from);
        }

        public override Expression Clone()
        {
            return new RangeExpression(From, To, Child.Clone());
        }

        public override void GetDependentLeafExpressions(ref List<LeafExpression> leafExpressions)
        {
            this.Child.GetDependentLeafExpressions(ref leafExpressions);
        }

        public override void RecursivilyInvokeDelegate(
            ExpressionDelegate expressionDelegate,
            Expression parent,
            object parameter
        )
        {
            expressionDelegate(this, parent, parameter);
            Child.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
        }

        public override string ToString()
        {
            if (To != From)
                return string.Format("{0}[{1}:{2}]", Child.ToString(), From, To);
            else
                return string.Format("{0}[{1}]", Child.ToString(), From);
        }
    }

    /// <summary>
    /// Negation and unary minus are unary expressions.
    /// </summary>
    public partial class UnaryExpression : Expression
    {
        private Expression child;
        public Expression Child
        {
            get { return child; }
            protected set { child = value; }
        }


        public override bool Signed
        {
            get
            {
                return Child.Signed;
            }
        }

        public override int Width
        {
            get
            {
                return Child.Width;
            }
        }

        protected UnaryExpression(ExpressionType exprType)
            : base(exprType)
        {
            this.Child = null;
        }

        public UnaryExpression(ExpressionType exprType, Expression child)
            :
          base(exprType)
        {
            this.Child = child;
        }

        public UnaryExpression(
            ExpressionType exprType,
            Expression child,
            Position startPosition,
            Position endPosition
        )
            : base(exprType, startPosition, endPosition)
        {
            this.Child = child;
        }

        public override Expression Clone()
        {
            return new UnaryExpression(ExpressionType, Child.Clone());
        }

        public override void GetDependentLeafExpressions(ref List<LeafExpression> leafExpressions)
        {
            this.Child.GetDependentLeafExpressions(ref leafExpressions);
        }

        public override void RecursivilyInvokeDelegate(
            ExpressionDelegate expressionDelegate,
            Expression parent,
            object parameter
        )
        {
            expressionDelegate(this, parent, parameter);
            Child.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
        }

        public override string ToString()
        {
            if (ExpressionType == ExpressionType.Not)
            {
                return string.Format("~{0}", Child.ToString());
            }
            else if (ExpressionType == ExpressionType.UnarySub)
            {
                return string.Format("-{0}", Child.ToString());
            }
            else
            {
                string message =
                    string.Format("Unexpected expression type '{0}'", ExpressionType.ToString());

                throw new NotImplementedException(message);
            }
        }
    }

    /// <summary>
    /// The IndexExpression are used when applying
    /// indexing to a lookup table.
    /// </summary>
    public partial class IndexExpression : Expression
    {
        private Expression identifier;
        public Expression Identifier
        {
            get { return identifier; }
            protected set { identifier = value; }
        }

        private Expression indexExpr;
        public Expression IndexExpr
        {
            get { return indexExpr; }
            protected set { indexExpr = value; }
        }

        public override bool Signed
        {
            get
            {
                return (Identifier as LeafExpression).ReferencedEntity.Signed;
            }
        }

        public override int Width
        {
            get
            {
                return (Identifier as LeafExpression).ReferencedEntity.Width;
            }
        }

        protected IndexExpression()
            : base(ExpressionType.Index)
        {
            this.Identifier = null;
            this.IndexExpr = null;
        }

        /// <summary>
        /// Constructs a new IndexExpression in which
        /// the indexing expression is applied to the
        /// identifier which must be a lookup table.
        /// </summary>
        /// <param name="identifier"></param>
        /// <param name="indexExpr"></param>
        public IndexExpression(Expression identifier, Expression indexExpr)
            :
          base(ExpressionType.Index)
        {
            this.Identifier = identifier;
            this.IndexExpr = indexExpr;
        }

        public IndexExpression(
            Expression identifier,
            Expression indexExpr,
            Position startPosition,
            Position endPosition
        )
            : base(ExpressionType.Index, startPosition, endPosition)
        {
            this.Identifier = identifier;
            this.IndexExpr = indexExpr;
        }

        public override Expression Clone()
        {
            return new IndexExpression(Identifier, IndexExpr.Clone());
        }

        public override void GetDependentLeafExpressions(ref List<LeafExpression> leafExpressions)
        {
            this.Identifier.GetDependentLeafExpressions(ref leafExpressions);
        }

        public override void RecursivilyInvokeDelegate(
            ExpressionDelegate expressionDelegate,
            Expression parent,
            object parameter
        )
        {
            expressionDelegate(this, parent, parameter);
            identifier.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
            indexExpr.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
        }

        public override string ToString()
        {
            return string.Format("{0}({1})", Identifier, IndexExpr.ToString());
        }
    }

    /// <summary>
    /// A BinaryExpression in an expression with
    /// two operands
    /// </summary>
    public partial class BinaryExpression : Expression
    {
        private Expression leftChild;
        public Expression LeftChild
        {
            get { return leftChild; }
            protected set { leftChild = value; }
        }

        private Expression rightChild;
        public Expression RightChild
        {
            get { return rightChild; }
            protected set { rightChild = value; }
        }

        public override bool Signed
        {
            get
            {
                switch (ExpressionType)
                {
                    case ExpressionType.Eq:
                    case ExpressionType.Neq:
                    case ExpressionType.Lt:
                    case ExpressionType.Lte:
                    case ExpressionType.Gt:
                    case ExpressionType.Gte:
                        return false;
                    default:
                        return LeftChild.Signed || RightChild.Signed;
                }
            }
        }

        public override int Width
        {
            get
            {
                switch (ExpressionType)
                {
                    case ExpressionType.Concatenation:
                        return LeftChild.Width + RightChild.Width;
                    case ExpressionType.ShiftLeft:
                        return LeftChild.Width + (1 << RightChild.Width);
                    case ExpressionType.Eq:
                    case ExpressionType.Neq:
                    case ExpressionType.Lt:
                    case ExpressionType.Lte:
                    case ExpressionType.Gt:
                    case ExpressionType.Gte:
                        return 1;
                    default:
                        return System.Math.Max(LeftChild.Width, RightChild.Width);
                }
            }
        }

        protected BinaryExpression()
            : base(ExpressionType.Unknown)
        {
            this.LeftChild = null;
            this.RightChild = null;
        }

        public BinaryExpression(ExpressionType exprType, Expression left, Expression right)
            : base(exprType)
        {
            this.LeftChild = left;
            this.RightChild = right;
        }

        public BinaryExpression(
            ExpressionType exprType,
            Expression left,
            Expression right,
            Position startPosition,
            Position endPosition
        )
            : base(exprType, startPosition, endPosition)
        {
            this.LeftChild = left;
            this.RightChild = right;
        }

        public override Expression Clone()
        {
            return new BinaryExpression(ExpressionType, LeftChild.Clone(), RightChild.Clone());
        }

        public override void GetDependentLeafExpressions(ref List<LeafExpression> leafExpressions)
        {
            if (ExpressionType == ExpressionType.Assignment)
            {
                this.RightChild.GetDependentLeafExpressions(ref leafExpressions);
            }
            else
            {
                this.LeftChild.GetDependentLeafExpressions(ref leafExpressions);
                this.RightChild.GetDependentLeafExpressions(ref leafExpressions);
            }
        }

        public override void RecursivilyInvokeDelegate(
            ExpressionDelegate expressionDelegate,
            Expression parent,
            object parameter
        )
        {
            expressionDelegate(this, parent, parameter);

            LeftChild.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
            RightChild.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
        }

        public override string ToString()
        {
            string symbol;
            switch (ExpressionType)
            {
                case ExpressionType.Add:
                    symbol = "+";
                    break;
                case ExpressionType.Sub:
                    symbol = "-";
                    break;
                case ExpressionType.Mul:
                    symbol = "*";
                    break;
                case ExpressionType.Div:
                    symbol = "/";
                    break;
                case ExpressionType.Mod:
                    symbol = "%";
                    break;
                case ExpressionType.Assignment:
                    symbol = "=";
                    break;
                case ExpressionType.Neq:
                    symbol = "!=";
                    break;
                case ExpressionType.Eq:
                    symbol = "==";
                    break;
                case ExpressionType.Gt:
                    symbol = ">";
                    break;
                case ExpressionType.Gte:
                    symbol = ">=";
                    break;
                case ExpressionType.Lt:
                    symbol = "<";
                    break;
                case ExpressionType.Lte:
                    symbol = "<=";
                    break;
                case ExpressionType.And:
                    symbol = "&";
                    break;
                case ExpressionType.Ior:
                    symbol = "|";
                    break;
                case ExpressionType.Xor:
                    symbol = "^";
                    break;
                case ExpressionType.ShiftLeft:
                    symbol = "<<";
                    break;
                case ExpressionType.ShiftRight:
                    symbol = ">>";
                    break;
                default:
                    throw new NotImplementedException();
            }

            bool leftChildParenthesis =
                      this.ExpressionType != ExpressionType.Assignment &&
                      (LeftChild is BinaryExpression || LeftChild is TernaryExpression);
            bool rightChildParenthesis =
                      this.ExpressionType != ExpressionType.Assignment &&
                      (RightChild is BinaryExpression || RightChild is TernaryExpression);

            if (leftChildParenthesis && rightChildParenthesis)
            {
                return string.Format("({0}) {1} ({2})", LeftChild.ToString(), symbol, RightChild.ToString());
            }
            else if (rightChildParenthesis)
            {
                return string.Format("{0} {1} ({2})", LeftChild.ToString(), symbol, RightChild.ToString());
            }
            else if (leftChildParenthesis)
            {
                return string.Format("({0}) {1} {2}", LeftChild.ToString(), symbol, RightChild.ToString());
            }
            else
            {
                return string.Format("{0} {1} {2}", LeftChild.ToString(), symbol, RightChild.ToString());
            }
        }
    }

    /// <summary>
    /// A BinaryExpression in an expression with
    /// two operands and a condition which selects
    /// one of them
    /// </summary>
    public partial class TernaryExpression : Expression
    {
        public readonly Expression Condition;
        public readonly Expression LeftChild;
        public readonly Expression RightChild;

        public override int Width
        {
            get
            {
                return System.Math.Max(LeftChild.Width, RightChild.Width);
            }
        }

        public override bool Signed
        {
            get
            {
                return LeftChild.Signed || RightChild.Signed;
            }
        }

        public TernaryExpression(Expression condition, Expression left, Expression right)
            :
          base(ExpressionType.Ternary)
        {
            this.Condition = condition;
            this.LeftChild = left;
            this.RightChild = right;
        }

        public TernaryExpression(
            Expression condition,
            Expression left,
            Expression right,
            Position startPosition,
            Position endPosition
        )
            : base(ExpressionType.Ternary, startPosition, endPosition)
        {
            this.Condition = condition;
            this.LeftChild = left;
            this.RightChild = right;
        }

        public override Expression Clone()
        {
            return new TernaryExpression(Condition.Clone(), LeftChild.Clone(), RightChild.Clone());
        }


        public override void GetDependentLeafExpressions(ref List<LeafExpression> leafExpressions)
        {
            this.Condition.GetDependentLeafExpressions(ref leafExpressions);
            this.LeftChild.GetDependentLeafExpressions(ref leafExpressions);
            this.RightChild.GetDependentLeafExpressions(ref leafExpressions);
        }

        public override void RecursivilyInvokeDelegate(
            ExpressionDelegate expressionDelegate,
            Expression parent,
            object parameter
        )
        {
            expressionDelegate(this, parent, parameter);
            Condition.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
            LeftChild.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
            RightChild.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
        }

        public override string ToString()
        {
            return string.Format("{0} ? {1} : {2}", Condition.ToString(), LeftChild.ToString(), RightChild.ToString());
        }
    }

    public partial class ListExpression : Expression
    {
        public readonly Expression[] List;

        public ListExpression(Expression[] list)
            : base(ExpressionType.List)
        {
            this.List = list;
        }

        public ListExpression(
            Expression[] list,
            Position startPosition,
            Position endPosition
        )
            : base(ExpressionType.List, startPosition, endPosition)
        {
            this.List = list;
        }

        public override Expression Clone()
        {
            List<Expression> clonedExpressions = new List<Expression>();
            foreach (Expression childExpr in List)
                clonedExpressions.Add(childExpr.Clone());

            return new ListExpression(clonedExpressions.ToArray());
        }


        public override void GetDependentLeafExpressions(ref List<LeafExpression> leafExpressions)
        {
            foreach (Expression expr in List)
                expr.GetDependentLeafExpressions(ref leafExpressions);
        }

        public override bool Signed
        {
            get
            {
                foreach (Expression expr in List)
                    if (expr.Signed)
                        return true;
                return false;
            }
        }

        public override int Width
        {
            get
            {
                int width = 0;
                foreach (Expression expr in List)
                    width = width < expr.Width ? expr.Width : width;
                return width;
            }
        }

        public override void RecursivilyInvokeDelegate(
            ExpressionDelegate expressionDelegate,
            Expression parent,
            object parameter
        )
        {
            expressionDelegate(this, parent, parameter);

            foreach (Expression e in List)
                e.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
        }

        /*
        public override string ToString()
        {
            StringBuilder str = new StringBuilder();
            foreach(Expression e in List)			
                str.Append(e.ToString() + ";\n");

            return str.ToString();
        }
         * */
    }

    public partial class DirectiveExpression : Expression
    {
        public readonly Expression[] Arguments;

        public override bool Signed
        {
            get { throw new global::System.NotSupportedException(); }
        }

        public override int Width
        {
            get { throw new global::System.NotSupportedException(); }
        }

        public DirectiveExpression(ExpressionType exprType, Expression[] arguments)
            : base(exprType)
        {
            this.Arguments = arguments;
        }

        public DirectiveExpression(
            ExpressionType exprType,
            Expression[] arguments,
            Position startPosition,
            Position endPosition
        )
            : base(exprType, startPosition, endPosition)
        {
            this.Arguments = arguments;
        }

        public DirectiveExpression(ExpressionType exprType)
            : base(exprType)
        {
            this.Arguments = null;
        }

        public DirectiveExpression(
            ExpressionType exprType,
            Position startPosition,
            Position endPosition
        )
            : base(exprType, startPosition, endPosition)
        {
            this.Arguments = null;
        }

        public override void GetDependentLeafExpressions(ref List<LeafExpression> leafExpressions)
        {
            if (Arguments != null)
                foreach (Expression expr in Arguments)
                    expr.GetDependentLeafExpressions(ref leafExpressions);
        }

        public override Expression Clone()
        {
            if (Arguments != null)
            {
                List<Expression> clonedExpressions = new List<Expression>();
                foreach (Expression childExpr in Arguments)
                    clonedExpressions.Add(childExpr.Clone());

                return new DirectiveExpression(ExpressionType, clonedExpressions.ToArray());
            }
            else
                return new DirectiveExpression(ExpressionType);
        }

        public override void RecursivilyInvokeDelegate(
            ExpressionDelegate expressionDelegate,
            Expression parent,
            object parameter
        )
        {
            expressionDelegate(this, parent, parameter);

            foreach (Expression argument in Arguments)
                argument.RecursivilyInvokeDelegate(expressionDelegate, this, parameter);
        }

        public override string ToString()
        {
            switch (ExpressionType)
            {
                case ExpressionType.DisplayDirective:
                    StringBuilder buffer = new StringBuilder("$display(");

                    foreach (Expression subExpr in Arguments)
                    {
                        buffer.AppendFormat("{0}, ", subExpr.ToString());
                    }
                    buffer.Remove(buffer.Length - 2, 2);
                    buffer.Append(")");
                    return buffer.ToString();
                case ExpressionType.FinishDirective:
                    return "$finish";
                case ExpressionType.CycleDirective:
                    return "$cycle";
                case ExpressionType.HexDirective:
                    return "$hex";
                case ExpressionType.DecDirective:
                    return "$dec";
                case ExpressionType.BinDirective:
                    return "$bin";
                case ExpressionType.SfgDirective:
                    return "$sfg";
                default:
                    throw new NotImplementedException();
            }
        }
    }
}